home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / ab20 / ab20_archive / utilities / printer / post-1.6src.lzh / postfont.c < prev    next >
C/C++ Source or Header  |  1991-04-17  |  52KB  |  1,536 lines

  1. /* PostScript interpreter file "postfont.c" - type 1 font routines */
  2. /* (C) Adrian Aylward 1989, 1991 */
  3.  
  4. # include "post.h"
  5.  
  6. /* # define FONTDEBUG Enable font debugging (make file does this) */
  7.  
  8. /* Character string execution data */
  9.  
  10. # define charmaxdepth    10
  11. # define charstacksize   24
  12.  
  13. static int charnest, charargn, charend, charaflag;
  14.  
  15. static float charstack[charstacksize], charargs[charstacksize];
  16.  
  17. static int charsbwlength, chardotsection, charflexn;
  18.  
  19. static float charsbw[4], charfptx[7], charfpty[7];
  20. static float charssx, charssy, charsdx, charsdy, charadx, charady;
  21. static float charcpx, charcpy;
  22.  
  23. /* Default overshoot suppression */
  24.  
  25. # define defbluescale  0.05
  26.  
  27. /* Stem value pair
  28.  *   Stems:
  29.  *     type = -1    base fixed
  30.  *             0    floating
  31.  *            +1    top fixed
  32.  *
  33.  *   Blues:
  34.  *     type = -1    blue - base alignment zone
  35.  *            +1    blue - top alignment zone
  36.  */
  37.  
  38. struct stem
  39. {   int type;
  40.     float s1, s2;
  41. };
  42.  
  43. # define maxblue         12
  44.  
  45. static int bluec;
  46. static struct stem bluev[maxblue];
  47.  
  48. static float bluescale, blueshift, bluefuzz;
  49.  
  50. # define maxstem         20
  51.  
  52. static int hstemc, vstemc;
  53. static struct stem hstemv[maxstem], vstemv[maxstem];
  54.  
  55. /* Stem transform
  56.  *     flag = -1    maps to x only
  57.  *             0    rotated, no hints
  58.  *            +1    maps to y only
  59.  *     type = -1    base/left of stem
  60.  *             0    inside stem
  61.  *            +1    top/right of stem
  62.  */
  63.  
  64. struct stform
  65. {   int flag, type;
  66.     struct stem *stem;
  67.     float z, fuzz, scale;
  68. };
  69.  
  70. struct stform hstform, vstform, bstform;
  71.  
  72. /* Routines */
  73.  
  74. extern void buildachar(int schar);
  75. extern void charstring(struct object *token1, int depth);
  76. extern void charpoint(struct point *ppoint);
  77. extern struct stem *charstem(struct stform *pstform,
  78.                              struct stem *pstem, int stemc);
  79. extern void charhint(struct point *ppoint, struct stform *pstform,
  80.                      struct stem *pstem, struct stem *pblue);
  81. extern void charfill(void);
  82. extern void charline(struct point *ppoint);
  83. extern void setxbuf(int size);
  84.  
  85.  
  86. /* Debugging procedures */
  87.  
  88. # ifdef FONTDEBUG
  89. # define FDEBUGN(s, n) fdebugn(depth, s, n)
  90. # else
  91. # define FDEBUGN(s, n)
  92. # endif
  93.  
  94. # ifdef FONTDEBUG
  95.  
  96. /* On the Amiga we can't redirect stderr, so use stdout instead */
  97.  
  98. # ifdef AMIGA
  99. # ifdef stderr
  100. # undef stderr
  101. # endif
  102. # define stderr stdout
  103. # endif
  104.  
  105. /* Debug mode values (bits)
  106.  *    1  Trace charstring commands
  107.  *    2  Trace path points
  108.  *    4  Trace hints
  109.  *    8  Display blues
  110.  */
  111.  
  112. int fontdebug;
  113.  
  114. /* setfontdebug */
  115.  
  116. void opsetfontdebug(void)
  117. {   struct object *token1;
  118.     if (opernest < 1) error(errstackunderflow);
  119.     token1 = &operstack[opernest - 1];
  120.     if (token1->type != typeint) error(errtypecheck);
  121.     fontdebug = token1->value.ival;
  122.     opernest--;
  123. }
  124.  
  125. /* Operator trace */
  126.  
  127. void fdebugn(int depth, char *sptr, int n)
  128. {   int i;
  129.     if (fontdebug & 1)
  130.     {   if (depth == 0)
  131.             fprintf(stderr, ">>");
  132.         else
  133.             fprintf(stderr, "%d>", depth);
  134.         fprintf(stderr, " (%4.0f,%4.0f) %2d %-13s ",
  135.                 charcpx, charcpy, charnest, sptr);
  136.         for (i = 0; i < n; i++)
  137.             fprintf(stderr, " %4.4g", charstack[i]);
  138.         fprintf(stderr, "\n");
  139.     }
  140. }
  141. # endif
  142.  
  143. /* Initialise type 1 fonts */
  144.  
  145. void initfont(void)
  146. {   xbsize = 0;
  147. # ifdef FONTDEBUG
  148.     systemop(opsetfontdebug,     "setfontdebug");
  149. # endif
  150. }
  151.  
  152. /* Initialise type 1 font build data */
  153.  
  154. void initbuild(vmref fdref)
  155. {   struct object token, *aptr;
  156.     struct stem blue;
  157.     int i;
  158.  
  159.     /* Extract the build data */
  160.  
  161.     fontmetrics = NULL;
  162.     if (dictget(fdref, &charname[charmetrics], &token, 0))
  163.     {   if (token.type != typedict) error(errinvalidfont);
  164.         fontmetrics = token.value.vref;
  165.     }
  166.     if (!dictget(fdref, &charname[charpainttype], &token, 0) ||
  167.         token.type != typeint ||
  168.         (token.value.ival != 0 && token.value.ival != 2))
  169.         error(errinvalidfont);
  170.     fontpainttype = token.value.ival;
  171.     if (fontpainttype != 0)
  172.     {   if (!dictget(fdref, &charname[charstrokewidth], &token, 0))
  173.             error(errinvalidfont);
  174.         if      (token.type == typeint)
  175.             fontstrokewidth = token.value.ival;
  176.         else if (token.type == typereal)
  177.             fontstrokewidth = token.value.rval;
  178.         else
  179.             error(errinvalidfont);
  180.     }
  181.     if (!dictget(fdref, &charname[charcharstrings], &token, 0) ||
  182.         token.type != typedict)
  183.         error(errinvalidfont);
  184.     fontcharstrings = token.value.vref;
  185.     if (!dictget(fdref, &charname[charprivate], &token, 0) ||
  186.         token.type != typedict)
  187.         error(errinvalidfont);
  188.     fontprivate = token.value.vref;
  189.     if (dictget(fontprivate, &charname[charsubrs], &fontsubrs, 0))
  190.     {   if (fontsubrs.type != typearray) error(errinvalidfont);
  191.     }
  192.     else
  193.         fontsubrs.length = 0;
  194.     if (dictget(fontprivate, &charname[charleniv], &token, 0))
  195.     {   if (token.type != typeint || token.value.ival < 0)
  196.             error(errinvalidfont);
  197.         fontleniv = token.value.ival;
  198.     }
  199.     else
  200.         fontleniv = 4;
  201.  
  202.     /* Extract the blues */
  203.  
  204.     bluec = 0;
  205.     if (dictget(fontprivate, &charname[charbluevalues], &token, 0))
  206.     {   if (token.type != typearray ||
  207.             token.length > maxblue + 2 || (token.length & 1))
  208.             error(errinvalidfont);
  209.         i = token.length >> 1;
  210.         aptr = vmaptr(token.value.vref);
  211.         blue.type = -1;
  212.         while (i--)
  213.         {   token = *aptr++;
  214.             if (token.type != typeint) error(errinvalidfont);
  215.             blue.s1 = token.value.ival;
  216.             token = *aptr++;
  217.             if (token.type != typeint) error(errinvalidfont);
  218.             blue.s2 = token.value.ival;
  219.             bluev[bluec++] = blue;
  220.             blue.type = 1;
  221.         }
  222.     }
  223.     if (dictget(fontprivate, &charname[charotherblues], &token, 0))
  224.     {   if (token.type != typearray ||
  225.             token.length > maxblue - 2 || (token.length & 1))
  226.             error(errinvalidfont);
  227.         i = token.length >> 1;
  228.         aptr = vmaptr(token.value.vref);
  229.         blue.type = -1;
  230.         while (i--)
  231.         {   token = *aptr++;
  232.             if (token.type != typeint) error(errinvalidfont);
  233.             blue.s1 = token.value.ival;
  234.             token = *aptr++;
  235.             if (token.type != typeint) error(errinvalidfont);
  236.             blue.s2 = token.value.ival;
  237.             bluev[bluec++] = blue;
  238.         }
  239.     }
  240.     bluescale = defbluescale;
  241.     if (dictget(fontprivate, &charname[charbluescale], &token, 0))
  242.     {   if      (token.type == typeint)
  243.             bluescale = token.value.ival;
  244.         else if (token.type == typereal)
  245.             bluescale = token.value.rval;
  246.         else
  247.             error(errinvalidfont);
  248.     }
  249.     blueshift = 7.0;
  250.     if (dictget(fontprivate, &charname[charblueshift], &token, 0))
  251.     {   if      (token.type == typeint)
  252.             blueshift = token.value.ival;
  253.         else
  254.             error(errinvalidfont);
  255.     }
  256.     bluefuzz = 1.0;
  257.     if (dictget(fontprivate, &charname[charbluefuzz], &token, 0))
  258.     {   if      (token.type == typeint)
  259.             bluefuzz = token.value.ival;
  260.         else
  261.             error(errinvalidfont);
  262.     }
  263. # ifdef FONTDEBUG
  264.     if (fontdebug & 8)
  265.     {   fprintf(stderr,   "-> Blues %2d", bluec);
  266.         for (i = 0; i < bluec; i++)
  267.             fprintf(stderr, " [%c,%4.0f,%4.0f]",
  268.                    (bluev[i].type < 0 ? '-' :  '+'),
  269.                    bluev[i].s1, bluev[i].s2);
  270.         fprintf(stderr, "\n-> BlueScale %6.4f BlueShift %2d BlueFuzz %d\n",
  271.                 bluescale, (int) blueshift, (int) bluefuzz);
  272.     }
  273. # endif
  274. }
  275.  
  276. /* Build a character */
  277.  
  278. void buildchar(int schar)
  279. {   struct object token1, token, *aptr;
  280.     struct point width, ll, ur, *ppoint;
  281.     float fdx, fdy;
  282.     int i;
  283.  
  284.     /* If the matrix is not rotated we can apply the hints */
  285.  
  286.     hstform.fuzz = vstform.fuzz = bstform.fuzz = 1.0;
  287.     for (i = 0; i < 4; i++)
  288.         if (fabs(gstate.ctm[i]) < .0001) gstate.ctm[i] = 0.0;
  289.     hstform.flag = 0;
  290.     if      (gstate.ctm[0] == 0.0 && gstate.ctm[2] != 0.0)
  291.     {   hstform.flag = -1;
  292.         hstform.scale = gstate.ctm[2];
  293.     }
  294.     else if (gstate.ctm[1] == 0.0 && gstate.ctm[3] != 0.0)
  295.     {   hstform.flag =  1;
  296.         hstform.scale = gstate.ctm[3];
  297.     }
  298.     vstform.flag = 0;
  299.     if      (gstate.ctm[0] != 0.0 && gstate.ctm[2] == 0.0)
  300.     {   vstform.flag = -1;
  301.         vstform.scale = gstate.ctm[0];
  302.     }
  303.     else if (gstate.ctm[1] != 0.0 && gstate.ctm[3] == 0.0)
  304.     {   vstform.flag =  1;
  305.         vstform.scale = gstate.ctm[1];
  306.     }
  307.  
  308.     /* Look up the name in the encoding vector */
  309.  
  310.     if (schar < fontencodlen)
  311.     {   token1 = vmaptr(fontencoding)[schar];
  312.         if (token1.type != typename) error(errinvalidfont);
  313.     }
  314.     else
  315.         token1 = charname[charnotdef];
  316.  
  317.     /* See if there is a metrics entry for this character */
  318.  
  319.     charsbwlength = 0;
  320.     charsbw[0] = charsbw[1] = charsbw[2] = charsbw[3] = 0.0;
  321.     if (fontmetrics != NULL && dictget(fontmetrics, &token1, &token, 0))
  322.     {   if (token.type == typearray)
  323.         {   if (token.length != 2 && token.length != 4)
  324.                 error(errinvalidfont);
  325.             i = token.length;
  326.             aptr = vmaptr(token.value.vref);
  327.         }
  328.         else
  329.         {   i = 1;
  330.             aptr = &token;
  331.         }
  332.         charsbwlength = i;
  333.         for (i = 0; i < charsbwlength; i++)
  334.         {   token = *aptr++;
  335.             if      (token.type == typeint)
  336.                 charsbw[i] = token.value.ival;
  337.             else if (token.type == typereal)
  338.                 charsbw[i] = token.value.rval;
  339.             else
  340.                 error(errinvalidfont);
  341.         }
  342.         if      (charsbwlength == 1)
  343.         {   charsbw[2] = charsbw[0];
  344.             charsbw[0] = 0.0;
  345.         }
  346.         else if (charsbwlength == 2)
  347.         {   charsbw[2] = charsbw[1];
  348.             charsbw[1] = 0.0;
  349.         }
  350.     }
  351.  
  352.     /* Execute the character string */
  353.  
  354.     charnest = charargn = 0;
  355.     charend = charaflag = chardotsection = 0;
  356.     charsdx = charsdy = 0.0;
  357.     charssx = charcpx = 0.0;
  358.     charssy = charcpy = 0.0;
  359.     fdx = gstate.ctm[4];
  360.     fdy = gstate.ctm[5];
  361.     gstate.ctm[4] = 0.0;
  362.     gstate.ctm[5] = 0.0;
  363.     charflexn = -1;
  364.     hstemc = vstemc = 0;
  365. # ifdef FONTDEBUG
  366.     if (fontdebug & 1)
  367.         fprintf(stderr, "/>%.*s\n",
  368.             vmnptr(token1.value.vref)->length,
  369.             vmnptr(token1.value.vref)->string);
  370. # endif
  371.     if (dictget(fontcharstrings, &token1,               &token, 0) ||
  372.         dictget(fontcharstrings, &charname[charnotdef], &token, 0))
  373.         charstring(&token, 0);
  374.  
  375.     /* Set the character width */
  376.  
  377.     width.type = 0;
  378.     width.x = charsbw[2];
  379.     width.y = charsbw[3];
  380.     dtransform(&width, gstate.ctm);
  381.     istate.pfcrec->width = width;
  382.  
  383.     /* For outlined fonts find the stroke path */
  384.  
  385.     gstate.flatness = 0.2;
  386.     if (fontpainttype != 0)
  387.     {   gstate.linewidth = fontstrokewidth;
  388.         if (istate.type == 1 ||
  389.             istate.type == 2 && gstate.cacheflag ||
  390.             istate.type == 3)
  391.         {   flattenpath();
  392.             strokepath(0);
  393.         }
  394.     }
  395.  
  396.     /* Calculate the bounding box and see if we can use the cache */
  397.  
  398.     if (istate.type >= 2)
  399.     {   i = gstate.pathend - gstate.pathbeg;
  400.         ppoint = &patharray[gstate.pathbeg];
  401.         if (i != 0)
  402.         {   ll = ur = *ppoint;
  403.             while (--i)
  404.             {   ppoint++;
  405.                 if (ppoint->x < ll.x) ll.x = ppoint->x;
  406.                 if (ppoint->x > ur.x) ur.x = ppoint->x;
  407.                 if (ppoint->y < ll.y) ll.y = ppoint->y;
  408.                 if (ppoint->y > ur.y) ur.y = ppoint->y;
  409.             }
  410.         }
  411.         else
  412.         {   ll.type = 0;
  413.             ll.x = 0.0;
  414.             ll.y = 0.0;
  415.             ur = ll;
  416.         }
  417.         setcachedevice(&ll, &ur, 1);
  418.         if (gstate.cacheflag)
  419.         {   fdx = gstate.ctm[4];
  420.             fdy = gstate.ctm[5];
  421.         }
  422.     }
  423.  
  424.     /* Adjust all the path coordinates */
  425.  
  426.     i = gstate.pathend - gstate.pathbeg;
  427.     ppoint = &patharray[gstate.pathbeg];
  428.     while (i--)
  429.     {   ppoint->x += fdx;
  430.         ppoint->y += fdy;
  431.         ppoint++;
  432.     }
  433.  
  434.     /* Fill the path */
  435.  
  436.     if      (istate.type < 2)
  437.         charpath();
  438.     else if (istate.type == 2 && !gstate.cacheflag)
  439.         gstate.pathend = gstate.pathbeg;
  440.     else
  441.     {   closepath(ptclosei);
  442.         if (fontpainttype == 0) flattenpath();
  443.         if (gstate.cacheflag)
  444.             charfill();
  445.         else
  446.         {   setupfill();
  447.             fill(gstate.pathbeg, gstate.pathend, -1);
  448.         }
  449.         gstate.pathend = gstate.pathbeg;
  450.     }
  451. }
  452.  
  453. /* Build an accent or character */
  454.  
  455. void buildachar(int schar)
  456. {   struct object token1, token;
  457.  
  458.     /* Look up the name in the standard encoding vector */
  459.  
  460.     token1 = stdencoding[schar];
  461.     if (token1.type != typename) error(errinvalidfont);
  462.  
  463.     /* Execute the character string */
  464.  
  465.     charnest = 0;
  466.     charend = 0;
  467.     chardotsection = 0;
  468.     charssx = charcpx;
  469.     charssy = charcpy;
  470.     hstemc = vstemc = 0;
  471. # ifdef FONTDEBUG
  472.     if (fontdebug & 1)
  473.         fprintf(stderr, "/>%.*s\n",
  474.             vmnptr(token1.value.vref)->length,
  475.             vmnptr(token1.value.vref)->string);
  476. # endif
  477.     if (dictget(fontcharstrings, &token1, &token, 0)) charstring(&token, 0);
  478. }
  479.  
  480. /* Interpret a character string */
  481.  
  482. void charstring(struct object *token1, int depth)
  483. {   struct object token;
  484.     struct point point;
  485.     char *sptr;
  486.     float dx1, dy1, dx2, dy2, dx3, dy3, dmin;
  487.     int length, erand, cx, ch, num, i;
  488.     int achar, bchar;
  489.  
  490.     if (token1->type != typestring) error(errinvalidfont);
  491.     length = token1->length;
  492.     if (length == 0) return;
  493.     sptr = vmsptr(token1->value.vref);
  494.  
  495.     /* Skip leading random bytes */
  496.  
  497.     i = fontleniv;
  498.     if (length < i) error(errinvalidfont);
  499.     length -= i;
  500.     erand = einitchar;
  501.     while (i--)
  502.     {   cx = *((unsigned char *) (sptr++));
  503.         erand = ((erand + cx) * ec1 + ec2) & emask;
  504.     }
  505.  
  506.     /* Interpret */
  507.  
  508.     while (length--)
  509.     {   cx = *((unsigned char *) (sptr++));
  510.         ch = cx ^ (erand >> eshift);
  511.         erand = ((erand + cx) * ec1 + ec2) & emask;
  512.  
  513.         /* Operator */
  514.  
  515.         if      (ch < 32)
  516.         {   switch (ch)
  517.             {   case 21:    /* rmoveto */
  518.                     FDEBUGN("rmoveto", 2);
  519.                     if (charnest < 2) error(errinvalidfont);
  520.                     dx1 = charstack[0];
  521.                     dy1 = charstack[1];
  522. rmoveto:            point.type = ptmove;
  523. movline:            point.x = charcpx = charcpx + dx1;
  524.                     point.y = charcpy = charcpy + dy1;
  525.                     if (charflexn < 0) charpoint(&point);
  526.                     charnest = 0;
  527.                     break;
  528.  
  529.                 case 22:    /* hmoveto */
  530.                     FDEBUGN("hmoveto", 1);
  531.                     if (charnest < 1) error(errinvalidfont);
  532.                     dx1 = charstack[0];
  533.                     dy1 = 0.0;
  534.                     goto rmoveto;
  535.  
  536.                 case  4:    /* vmoveto */
  537.                     FDEBUGN("vmoveto", 1);
  538.                     if (charnest < 1) error(errinvalidfont);
  539.                     dx1 = 0.0;
  540.                     dy1 = charstack[0];
  541.                     goto rmoveto;
  542.  
  543.                 case  5:    /* rlineto */
  544.                     FDEBUGN("rlineto", 2);
  545.                     if (charnest < 2) error(errinvalidfont);
  546.                     dx1 = charstack[0];
  547.                     dy1 = charstack[1];
  548. rlineto:            point.type = ptline;
  549.                     if (gstate.pathbeg == gstate.pathend)
  550.                         error(errinvalidfont);
  551.                     goto movline;
  552.  
  553.                 case  6:    /* hlineto */
  554.                     FDEBUGN("hlineto", 1);
  555.                     if (charnest < 1) error(errinvalidfont);
  556.                     dx1 = charstack[0];
  557.                     dy1 = 0.0;
  558.                     goto rlineto;
  559.  
  560.                 case  7:    /* vlineto */
  561.                     FDEBUGN("vlineto", 1);
  562.                     if (charnest < 1) error(errinvalidfont);
  563.                     dx1 = 0.0;
  564.                     dy1 = charstack[0];
  565.                     goto rlineto;
  566.  
  567.                 case  8:    /* rrcurveto */
  568.                     FDEBUGN("rrcurveto", 6);
  569.                     if (charnest < 6) error(errinvalidfont);
  570.                     dx1 = charstack[0];
  571.                     dy1 = charstack[1];
  572.                     dx2 = charstack[2];
  573.                     dy2 = charstack[3];
  574.                     dx3 = charstack[4];
  575.                     dy3 = charstack[5];
  576. rrcurveto:          point.type = ptcurve;
  577.                     if (gstate.pathbeg == gstate.pathend)
  578.                         error(errinvalidfont);
  579.                     point.x = charcpx + dx1;
  580.                     point.y = charcpy + dy1;
  581.                     charpoint(&point);
  582.                     point.x += dx2;
  583.                     point.y += dy2;
  584.                     charpoint(&point);
  585.                     charcpx = point.x = point.x + dx3;
  586.                     charcpy = point.y = point.y + dy3;
  587.                     charpoint(&point);
  588.                     charnest = 0;
  589.                     break;
  590.  
  591.                 case 30:    /* vhcurveto */
  592.                     FDEBUGN("vhcurveto", 4);
  593.                     if (charnest < 4) error(errinvalidfont);
  594.                     dx1 = 0.0;
  595.                     dy1 = charstack[0];
  596.                     dx2 = charstack[1];
  597.                     dy2 = charstack[2];
  598.                     dx3 = charstack[3];
  599.                     dy3 = 0.0;
  600.                     goto rrcurveto;
  601.  
  602.                 case 31:    /* hvcurveto */
  603.                     FDEBUGN("hvcurveto", 4);
  604.                     if (charnest < 4) error(errinvalidfont);
  605.                     dx1 = charstack[0];
  606.                     dy1 = 0.0;
  607.                     dx2 = charstack[1];
  608.                     dy2 = charstack[2];
  609.                     dx3 = 0.0;
  610.                     dy3 = charstack[3];
  611.                     goto rrcurveto;
  612.  
  613.                 case  9:    /* closepath */
  614.                     FDEBUGN("closepath", 0);
  615.                     closepath(ptclosex);
  616.                     charnest = 0;
  617.                     break;
  618.  
  619.                 case 10:    /* callsubr */
  620.                     FDEBUGN("callsubr", charnest);
  621.                     if (charnest < 1) error(errinvalidfont);
  622.                     i = itrunc(charstack[charnest - 1]);
  623.                     if (i < 0 || i > fontsubrs.length) error(errinvalidfont);
  624.                     charnest--;
  625.                     token = vmaptr(fontsubrs.value.vref)[i];
  626.                     if (depth + 1 == charmaxdepth) error(errinvalidfont);
  627.                     charstring(&token, depth + 1);
  628.                     break;
  629.  
  630.                 case 11:    /* return */
  631.                     FDEBUGN("return", 0);
  632.                     if (depth == 0) error(errinvalidfont);
  633.                     return;
  634.  
  635.                 case 14:    /* endchar */
  636.                     FDEBUGN("endchar", 0);
  637.                     charnest = 0;
  638.                     charend = 1;
  639.                     break;
  640.  
  641.                 case 13:    /* hsbw */
  642.                     FDEBUGN("hsbw", 2);
  643.                     if (charnest < 2) error(errinvalidfont);
  644.                     dx1 = charstack[0];
  645.                     dy1 = 0.0;
  646.                     dx2 = charstack[1];
  647.                     dy2 = 0.0;
  648. sbw:                if      (charaflag == 1)
  649.                     {   charcpx = dx1 + charsdx;
  650.                         charcpy = dy1 + charsdy;
  651.                         charadx += charcpx;
  652.                         charady += charcpy;
  653.                     }
  654.                     else if (charaflag == 2)
  655.                     {   charcpx = charadx;
  656.                         charcpy = charady;
  657.                     }
  658.                     else
  659.                     {   if      (charsbwlength == 0)
  660.                         {   charsbw[0] = dx1;
  661.                             charsbw[1] = dy1;
  662.                             charsbw[2] = dx2;
  663.                             charsbw[3] = dy2;
  664.                         }
  665.                         else if (charsbwlength == 1)
  666.                         {   charsbw[0] = dx1;
  667.                             charsbw[1] = dy1;
  668.                         }
  669.                         charcpx = charsbw[0];
  670.                         charcpy = charsbw[1];
  671.                         charsdx = charcpx - dx1;
  672.                         charsdy = charcpy - dy1;
  673.                     }
  674.                     charssx = charcpx;
  675.                     charssy = charcpy;
  676.                     charnest = 0;
  677.                     break;
  678.  
  679.                 case  1:    /* hstem */
  680.                     FDEBUGN("hstem", 2);
  681.                     if (charnest < 2) error(errinvalidfont);
  682.                     dy1 = charssy + charstack[0];
  683.                     dy2 = dy1 + charstack[1];
  684.                     if (dy1 > dy2)
  685.                     {   dy3 = dy1;
  686.                         dy1 = dy2;
  687.                         dy2 = dy3;
  688.                     }
  689.                     if (hstemc < maxstem)
  690.                     {   hstemv[hstemc].s1 = dy1;
  691.                         hstemv[hstemc].s2 = dy2;
  692.                         hstemc++;
  693.                     }
  694.                     charnest = 0;
  695.                     break;
  696.  
  697.                 case  3:    /* vstem */
  698.                     FDEBUGN("vstem", 2);
  699.                     if (charnest < 2) error(errinvalidfont);
  700.                     dx1 = charssx + charstack[0];
  701.                     dx2 = dx1 + charstack[1];
  702.                     if (dx1 > dx2)
  703.                     {   dx3 = dx1;
  704.                         dx1 = dx2;
  705.                         dx2 = dx3;
  706.                     }
  707.                     if (vstemc < maxstem)
  708.                     {   vstemv[vstemc].s1 = dx1;
  709.                         vstemv[vstemc].s2 = dx2;
  710.                         vstemc++;
  711.                     }
  712.                     charnest = 0;
  713.                     break;
  714.  
  715.                 case 15:    /* moveto  +++ UNDOCUMENTED, OBSOLETE +++ */
  716.                     FDEBUGN("MOVETO", 2);
  717.                     if (charnest < 2) error(errinvalidfont);
  718.                     dx1 = charstack[0] + charssx - charcpx;
  719.                     dy1 = charstack[1] + charssy - charcpy;
  720.                     goto rmoveto;
  721.  
  722.                 case 16:    /* lineto  +++ UNDOCUMENTED, OBSOLETE +++ */
  723.                     FDEBUGN("LINETO", 2);
  724.                     if (charnest < 2) error(errinvalidfont);
  725.                     dx1 = charstack[0] + charssx - charcpx;
  726.                     dy1 = charstack[1] + charssy - charcpy;
  727.                     goto rlineto;
  728.  
  729.                 case 17:    /* curveto +++ UNDOCUMENTED, OBSOLETE +++ */
  730.                     FDEBUGN("CURVETO", 6);
  731.                     if (charnest < 6) error(errinvalidfont);
  732.                     dx1 = charstack[0] + charssx - charcpx;
  733.                     dy1 = charstack[1] + charssy - charcpy;
  734.                     dx2 = charstack[2] + charssx - charcpx;
  735.                     dy2 = charstack[3] + charssy - charcpy;
  736.                     dx3 = charstack[4] + charssx - charcpx;
  737.                     dy3 = charstack[5] + charssy - charcpy;
  738.                     goto rrcurveto;
  739.  
  740.                 case 12:    /* ... */
  741.                     if (length == 0) error(errinvalidfont);
  742.                     length--;
  743.                     cx = *((unsigned char *) (sptr++));
  744.                     ch = cx ^ (erand >> eshift);
  745.                     erand = ((erand + cx) * ec1 + ec2) & emask;
  746.                     switch (ch)
  747.                     {   case  0:    /* dotsection */
  748.                             FDEBUGN("dotsection", 0);
  749.                             chardotsection = !chardotsection;
  750.                             charnest = 0;
  751.                             break;
  752.  
  753.                         case  1:    /* vstem3 */
  754.                             FDEBUGN("vstem3", 6);
  755.                             if (charnest < 6) error(errinvalidfont);
  756.                             vstemv[0].s1 =
  757.                                 charssx + charstack[0];
  758.                             vstemv[0].s2 =
  759.                                 charssx + charstack[0] + charstack[1];
  760.                             vstemv[1].s1 =
  761.                                 charssx + charstack[2];
  762.                             vstemv[1].s2 =
  763.                                 charssx + charstack[2] + charstack[3];
  764.                             vstemv[2].s1 =
  765.                                 charssx + charstack[4];
  766.                             vstemv[2].s2 =
  767.                                 charssx + charstack[4] + charstack[5];
  768.                             vstemc = 3;
  769.                             charnest = 0;
  770.                             break;
  771.  
  772.                         case  2:    /* hstem3 */
  773.                             FDEBUGN("hstem3", 6);
  774.                             if (charnest < 6) error(errinvalidfont);
  775.                             hstemv[0].s1 =
  776.                                 charssy + charstack[0];
  777.                             hstemv[0].s2 =
  778.                                 charssy + charstack[0] + charstack[1];
  779.                             hstemv[1].s1 =
  780.                                 charssy + charstack[2];
  781.                             hstemv[1].s2 =
  782.                                 charssy + charstack[2] + charstack[3];
  783.                             hstemv[2].s1 =
  784.                                 charssy + charstack[4];
  785.                             hstemv[2].s2 =
  786.                                 charssy + charstack[4] + charstack[5];
  787.                             hstemc = 3;
  788.                             charnest = 0;
  789.                             break;
  790.  
  791.                         case  6:    /* seac */
  792.                             FDEBUGN("seac", 5);
  793.                             if (charnest < 5) error(errinvalidfont);
  794.                             bchar = itrunc(charstack[3]);
  795.                             achar = itrunc(charstack[4]);
  796.                             if (charaflag) error(errinvalidfont);
  797.                             charadx = charstack[1];
  798.                             charady = charstack[2];
  799.                             charaflag = 1;
  800.                             charcpx = 0.0;
  801.                             charcpy = 0.0;
  802.                             buildachar(bchar);
  803.                             charaflag = 2;
  804.                             charcpx = charadx;
  805.                             charcpy = charady;
  806.                             buildachar(achar);
  807.                             charnest = 0;
  808.                             charend = 1;
  809.                             break;
  810.  
  811.                         case  7:    /* sbw */
  812.                             FDEBUGN("sbw", 4);
  813.                             if (charnest < 4) error(errinvalidfont);
  814.                             dx1 = charstack[0];
  815.                             dy1 = charstack[1];
  816.                             dx2 = charstack[2];
  817.                             dy2 = charstack[3];
  818.                             goto sbw;
  819.  
  820.                         case 12:    /* div */
  821.                             FDEBUGN("div", charnest);
  822.                             if (charnest < 2) error(errinvalidfont);
  823.                             charstack[charnest - 2] /=
  824.                                     charstack[charnest - 1];
  825.                             charnest--;
  826.                             break;
  827.  
  828.                         case 16:    /* callothersubr */
  829.                             FDEBUGN("callothersubr", charnest);
  830.                             if (charnest < 2) error(errinvalidfont);
  831.                             i = itrunc(charstack[charnest - 1]);
  832.                             num = itrunc(charstack[charnest - 2]);
  833.                             charnest -= 2;
  834.                             if (num < 0 || num > charnest)
  835.                                 error(errinvalidfont);
  836.                             charargn = 0;
  837.                             while (num--)
  838.                                 charargs[charargn++] = charstack[--charnest];
  839.                             switch (i)
  840.                             {   case 0: /* Flex */
  841.                                     if (charargn != 3)
  842.                                         error(errinvalidfont);
  843.                                     dmin = fabs(charargs[2]) / 100.0;
  844.                                     charargn--;
  845.                                     if (charflexn != 7)
  846.                                         error(errinvalidfont);
  847.                                     charflexn = -1;
  848.                                     point.x = charfptx[3] - charfptx[0];
  849.                                     point.y = charfpty[3] - charfpty[0];
  850.                                     if
  851.                             (fabs(charfptx[3] - charcpx) > 20.0 &&
  852.                              fabs(charfpty[3] - charcpy) > 20.0)
  853.                                         goto flexc;
  854.                                     if
  855.                             (fabs(charfptx[3] - charfptx[6]) > 20.0 &&
  856.                              fabs(charfpty[3] - charfpty[6]) > 20.0)
  857.                                         goto flexc;
  858.                                     dtransform(&point, gstate.ctm);
  859.                                     point.x = fabs(point.x);
  860.                                     point.y = fabs(point.y);
  861.                                     if ((point.x < .01 && point.y < dmin) ||
  862.                                         (point.y < .01 && point.x < dmin))
  863.                                     {   point.type = ptline;
  864.                                         point.x = charfptx[6];
  865.                                         point.y = charfpty[6];
  866.                                         charpoint(&point);
  867.                                         break;
  868.                                     }
  869. flexc:                              point.type = ptcurve;
  870.                                     for (i = 1; i < 7; i++)
  871.                                     {   point.x = charfptx[i];
  872.                                         point.y = charfpty[i];
  873.                                         charpoint(&point);
  874.                                     }
  875.                                     break;
  876.  
  877.                                 case 1: /* Flex */
  878.                                     if (charargn != 0)
  879.                                         error(errinvalidfont);
  880.                                     if (charflexn >= 0)
  881.                                         error(errinvalidfont);
  882.                                     charflexn = 0;
  883.                                     break;
  884.  
  885.                                 case 2: /* Flex */
  886.                                     if (charargn != 0)
  887.                                         error(errinvalidfont);
  888.                                     if (charflexn > 6)
  889.                                         error(errinvalidfont);
  890.                                     charfptx[charflexn] = charcpx;
  891.                                     charfpty[charflexn] = charcpy;
  892.                                     charflexn++;
  893.                                     break;
  894.  
  895.                                 case 3: /* Hint replacement */
  896.                                     hstemc = vstemc = 0;
  897.                                     break;
  898.                             }
  899.                             break;
  900.  
  901.                         case 17:    /* pop */
  902.                             FDEBUGN("pop", 0);
  903.                             if (charnest == charstacksize || charargn == 0)
  904.                                 error(errinvalidfont);
  905.                             charstack[charnest++] = charargs[--charargn];
  906.                             break;
  907.  
  908.                         case 32:    /* pushcurrentpoint */
  909.                                     /*     +++ UNDOCUMENTED, OBSOLETE +++ */
  910.                             FDEBUGN("PUSHCURRENTPOINT", 0);
  911.                             if (charnest + 2 > charstacksize)
  912.                                 error(errinvalidfont);
  913.                             charstack[charnest++] = charcpx;
  914.                             charstack[charnest++] = charcpy;
  915.                             break;
  916.  
  917.                         case 33:    /* setcurrentpoint */
  918.                             FDEBUGN("setcurrentpoint", 2);
  919.                             if (charnest < 2) error(errinvalidfont);
  920.                             charcpx = charstack[0];
  921.                             charcpy = charstack[1];
  922.                             charnest = 0;
  923.                             break;
  924.  
  925.                         default:
  926.                             error(errinvalidfont);
  927.                     }
  928.                     break;
  929.  
  930.                 default:
  931.                     error(errinvalidfont);
  932.  
  933.             }
  934.             if (charend) return;
  935.         }
  936.  
  937.         /* Number */
  938.  
  939.         else
  940.         {   if      (ch < 247)
  941.                 num = ch - 139;
  942.             else if (ch == 255)
  943.             {   if (length < 4) error(errinvalidfont);
  944.                 length -= 4;
  945.                 num = 0;
  946.                 i = 4;
  947.                 while (i--)
  948.                 {   cx = *((unsigned char *) (sptr++));
  949.                     ch = cx ^ (erand >> eshift);
  950.                     erand = ((erand + cx) * ec1 + ec2) & emask;
  951.                     num = (num << 8) | ch;
  952.                 }
  953.             }
  954.             else
  955.             {   if (length == 0) error(errinvalidfont);
  956.                 length--;
  957.                 num = ch;
  958.                 cx = *((unsigned char *) (sptr++));
  959.                 ch = cx ^ (erand >> eshift);
  960.                 erand = ((erand + cx) * ec1 + ec2) & emask;
  961.                 if (num < 251)
  962.                     num =   (num - 247) * 256 + ch + 108;
  963.                 else
  964.                     num = -((num - 251) * 256 + ch + 108);
  965.             }
  966.             if (charnest == charstacksize) error(errinvalidfont);
  967.             charstack[charnest++] = num;
  968.         }
  969.     }
  970. }
  971.  
  972. /* Add a point to the character path */
  973.  
  974. void charpoint(struct point *ppoint)
  975. {   struct point point;
  976.     struct stem *pstem, *pblue;
  977.  
  978.     /* Transform to device space, rounding to multiples of 1/16 */
  979.  
  980.     point = *ppoint;
  981.     dtransform(&point, gstate.ctm);
  982.     point.x = floor(point.x * 16.0 + 0.5) / 16.0;
  983.     point.y = floor(point.y * 16.0 + 0.5) / 16.0;
  984.  
  985.     /* See if the point is within a hstem.  If it is, see if it is within an
  986.      * alignment zone.  Even if the point is not within an alignment zone,
  987.      * the stem may be, and we need to know which edge of it is fixed by the
  988.      * alignment.  Then apply any hint */
  989.  
  990.     if (hstform.flag != 0)
  991.     {   pstem = pblue = NULL;
  992.         hstform.z = ppoint->y;
  993.         if (!chardotsection)
  994.         {   pstem = charstem(&hstform, hstemv, hstemc);
  995.             if (pstem)
  996.             {   pstem->type = 0;
  997.                 bstform.z = pstem->s1;
  998.                 pblue = charstem(&bstform, bluev, bluec);
  999.                 if (pblue && pblue->type < 0)
  1000.                     pstem->type = -1;
  1001.                 else
  1002.                 {   bstform.z = pstem->s2;
  1003.                     pblue = charstem(&bstform, bluev, bluec);
  1004.                     if (pblue && pblue->type > 0)
  1005.                         pstem->type =  1;
  1006.                 }
  1007.             }
  1008.         }
  1009.         charhint(&point, &hstform, pstem, pblue);
  1010.     }
  1011.  
  1012.     /* See if the point is within a vstem.  Then apply any hint */
  1013.  
  1014.     if (vstform.flag != 0)
  1015.     {   pstem = pblue = NULL;
  1016.         vstform.z = ppoint->x;
  1017.         if (!chardotsection)
  1018.         {   pstem = charstem(&vstform, vstemv, vstemc);
  1019.             if (pstem)
  1020.                 pstem->type = 0;
  1021.         }
  1022.         charhint(&point, &vstform, pstem, NULL);
  1023.     }
  1024.  
  1025. # ifdef FONTDEBUG
  1026.     if (fontdebug & 2)
  1027.         fprintf(stderr, ".> (%4.0f,%4.0f) [%7.2f,%7.2f]\n",
  1028.                 ppoint->x, ppoint->y, point.x, point.y);
  1029. # endif
  1030.     if (point.type == ptmove)
  1031.     {   closepath(ptclosei);
  1032.         if (gstate.pathbeg != gstate.pathend &&
  1033.             patharray[gstate.pathend - 1].type == ptmove)
  1034.             gstate.pathend--;
  1035.     }
  1036.     checkpathsize(gstate.pathend + 1);
  1037.     patharray[gstate.pathend++] = point;
  1038. }
  1039.  
  1040. /* See if a coordinate is within a stem */
  1041.  
  1042. struct stem *charstem(struct stform *pstform, struct stem *pstem, int stemc)
  1043. {   while (stemc--)
  1044.     {   if (fabs(pstform->z - pstem->s1) <= pstform->fuzz)
  1045.         {   pstform->type = -1; /* Bottom/left */
  1046.             return pstem;
  1047.         }
  1048.         if (fabs(pstform->z - pstem->s2) <= pstform->fuzz)
  1049.         {   pstform->type =  1; /* Top/right */
  1050.             return pstem;
  1051.         }
  1052.         if (pstform->z > pstem->s1 && pstform->z < pstem->s2)
  1053.         {   pstform->type =  0; /* Inside */
  1054.             return pstem;
  1055.         }
  1056.         pstem++;
  1057.     }
  1058.     return NULL;
  1059. }
  1060.  
  1061. /* Apply a hint */
  1062.  
  1063. void charhint(struct point *ppoint, struct stform *pstform,
  1064.               struct stem *pstem, struct stem *pblue)
  1065. {   float z1, z2, s1, s2, s, w1, w2, w, d, f;
  1066.     int iw;
  1067.  
  1068.     /* Get the coordinate */
  1069.  
  1070.     if (pstform->flag < 0)
  1071.         z1 = ppoint->x;
  1072.     else
  1073.         z1 = ppoint->y;
  1074.     z2 = z1;
  1075.  
  1076.     /* If within a stem calculate its width and regularise it.  Don't
  1077.      * adjust very small widths */
  1078.  
  1079.     if (pstem)
  1080.     {   s1 = pstem->s1 * pstform->scale;
  1081.         s2 = pstem->s2 * pstform->scale;
  1082.         w1 = fabs(s2 - s1);
  1083.         if (w1 < 0.5)
  1084.         {  w2 = 0.75;
  1085.            iw = 1;
  1086.         }
  1087.         else
  1088.         {  w2 = floor(w1 + 0.5);
  1089.            iw = w2;
  1090.            w2 -= 0.25;
  1091.         }
  1092.         if (s1 < s2)
  1093.             w =  w2;
  1094.         else
  1095.             w = -w2;
  1096.  
  1097.         /* If a stem boundary falls within an alignment zone then align the
  1098.          * stem if the scale is less than BlueScale or if its under/overshoot
  1099.          * distance is less then BlueShift and less than half a pixel.
  1100.          * Also the coordinate if necessary, also if its device space
  1101.          * coordinate is in the alignment zone, due to rounding.  Bottom
  1102.          * zones (device space) are aligned at 0.0625, top zones at 0.9375
  1103.          */
  1104.  
  1105.         if      (pstem->type < 0)
  1106.         {   s = pblue->s2 * pstform->scale;
  1107.             if (pstform->scale < 0.0)
  1108.                 s = floor(s - 0.4375) + 0.9375;
  1109.             else
  1110.                 s = floor(s + 0.4375) + 0.0625;
  1111.             f = fabs(pstform->scale);
  1112.             d = pblue->s2 - pstem->s1;
  1113.             if (f < bluescale || (d < blueshift && d * f < 0.5))
  1114.                 s1 = s;
  1115.             else
  1116.                 s1 = s - floor(d * pstform->scale * 16.0 + 0.5) / 16.0;
  1117.             s2 = s1 + w;
  1118.             d = pblue->s2 - pstform->z;
  1119.             if (pstform->z <= pblue->s2 + bluefuzz)
  1120.             {   if (f < bluescale || (d < blueshift && d * f < 0.5))
  1121.                     goto align;
  1122.             }
  1123.             else
  1124.                 if (pstform->type == 0 &&
  1125.                     (pstform->scale < 0.0 ? z2 > s : z2 < s)) goto align;
  1126.         }
  1127.         else if (pstem->type > 0)
  1128.         {   s = pblue->s1 * pstform->scale;
  1129.             if (pstform->scale < 0.0)
  1130.                 s = floor(s + 0.4375) + 0.0625;
  1131.             else
  1132.                 s = floor(s - 0.4375) + 0.9375;
  1133.             f = fabs(pstform->scale);
  1134.             d = pstem->s2 - pblue->s1;
  1135.             if (f < bluescale || (d < blueshift && d * f < 0.5))
  1136.                 s2 = s;
  1137.             else
  1138.                 s2 = s + floor(d * pstform->scale * 16.0 + 0.5) / 16.0;
  1139.             s1 = s2 - w;
  1140.             d = pstform->z - pblue->s1;
  1141.             if (pstform->z >= pblue->s1 - bluefuzz)
  1142.             {   if (f < bluescale || (d < blueshift && d * f < 0.5))
  1143.                     goto align;
  1144.             }
  1145.             else
  1146.                 if (pstform->type == 0 &&
  1147.                     (pstform->scale < 0.0 ? z2 < s : z2 > s)) goto align;
  1148.         }
  1149.  
  1150.         /* If a stem is not subject to alignment, odd widths are centred
  1151.          * on 0.4375 pixels, even widths on 0.9365 pixels. */
  1152.  
  1153.         else
  1154.         {   if (w2 > 0.5)
  1155.             {   s = (s1 + s2) / 2.0;
  1156.                 if (iw & 1)
  1157.                     s = floor(s + 0.0625) + 0.4375;
  1158.                 else
  1159.                     s = floor(s + 0.5625) - 0.0625;
  1160.                 w = w / 2.0;
  1161.                 s1 = s - w;
  1162.                 s2 = s + w;
  1163.             }
  1164.         }
  1165.  
  1166.         /* If we are at one of the stem edges adjust our position to match;
  1167.          * otherwise just ensure we remain within the stem */
  1168.  
  1169.         if      (pstform->type < 0)
  1170.             z2 = s1;
  1171.         else if (pstform->type > 0)
  1172.             z2 = s2;
  1173.         else
  1174.         {   if (s1 < s2)
  1175.             {   if (z2 < s1) z2 = s1;
  1176.                 if (z2 > s2) z2 = s2;
  1177.             }
  1178.             else
  1179.             {   if (z2 < s2) z2 = s2;
  1180.                 if (z2 > s1) z2 = s1;
  1181.             }
  1182.         }
  1183.  
  1184. # ifdef FONTDEBUG
  1185.         if (fontdebug & 4 && z1 != z2)
  1186.             fprintf(stderr, "=> StemW %7.2f -> %7.2f [%6.2f -> %6.2f]\n",
  1187.                     z1, z2, w1, w2);
  1188. # endif
  1189.         goto setval;
  1190.  
  1191. align:
  1192.         z2 = s;
  1193. # ifdef FONTDEBUG
  1194.         if (fontdebug & 4 && z1 != z2)
  1195.             fprintf(stderr, "=> Align %7.2f -> %7.2f\n",
  1196.                     z1, z2);
  1197. # endif
  1198.     }
  1199.  
  1200.     /* Set the coordinate value */
  1201.  
  1202. setval:
  1203.     if (pstform->flag < 0)
  1204.         ppoint->x = z2;
  1205.     else
  1206.         ppoint->y = z2;
  1207. }
  1208.  
  1209. /* Bit packing tables to compress to one bit per pixel without dropouts */
  1210.  
  1211. static unsigned char ctbl[256] = /* Bit(s) in center (not edges) */
  1212. {   0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 */
  1213.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 */
  1214.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 */
  1215.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 */
  1216.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 */
  1217.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 */
  1218.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 */
  1219.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 70 */
  1220.     0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, /* 80 */
  1221.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 90 */
  1222.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* a0 */
  1223.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* b0 */
  1224.     0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, /* c0 */
  1225.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* d0 */
  1226.     0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, /* e0 */
  1227.     0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1  /* f0 */
  1228. };
  1229.  
  1230. static unsigned char ltbl[256] = /* Number of bits at left */
  1231. {   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */
  1232.     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 */
  1233.     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 */
  1234.     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 30 */
  1235.     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 */
  1236.     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 50 */
  1237.     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 */
  1238.     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 70 */
  1239.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 80 */
  1240.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 90 */
  1241.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* a0 */
  1242.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* b0 */
  1243.     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* c0 */
  1244.     0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* d0 */
  1245.     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* e0 */
  1246.     4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8  /* f0 */
  1247. };
  1248.  
  1249. static unsigned char rtbl[256] = /* Number of bits at right */
  1250. {   0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /* 00 */
  1251.     0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, /* 10 */
  1252.     0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /* 20 */
  1253.     0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, /* 30 */
  1254.     0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /* 40 */
  1255.     0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, /* 50 */
  1256.     0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /* 60 */
  1257.     0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 7, /* 70 */
  1258.     0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /* 80 */
  1259.     0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, /* 90 */
  1260.     0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /* a0 */
  1261.     0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, /* b0 */
  1262.     0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /* c0 */
  1263.     0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, /* d0 */
  1264.     0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /* e0 */
  1265.     0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 8  /* f0 */
  1266. };
  1267.  
  1268. /* Fill a character path, no clipping needed */
  1269.  
  1270. void charfill(void)
  1271. {   struct point *ppoint;
  1272.     struct line *pline, **ppline;
  1273.     char *pptr, *pptr1;         /* device buffer pointers */
  1274.     char *xptr1, *xptr2;        /* x buffer pointers */
  1275.     int count;                  /* counter */
  1276.     int active, discard, sort;  /* lines active, to be discarded, sorted */
  1277.     int yy;                     /* current y coordinate */
  1278.     int x1, x2, xp, xx;         /* current, previous x position range */
  1279.     int fdir;                   /* fill direction counter */
  1280.     int mask1, mask2;           /* bit masks for first and last bytes */
  1281.     int s0, s1, s2;             /* segment to draw */
  1282.  
  1283.     /* Set up the fill lines and y buckets.  Set up the x buffer */
  1284.  
  1285.     lineend = 0;
  1286.     count = gstate.pathend - gstate.pathbeg;
  1287.     ppoint = &patharray[gstate.pathbeg];
  1288.     while (count--)
  1289.     {   if (ppoint->type != ptmove) charline(ppoint - 1);
  1290.         ppoint++;
  1291.     }
  1292.     setybucket(0, gstate.dev.ysize * 8);
  1293.     setxbuf(gstate.dev.xsize);
  1294.     memset((char *) xshf, 0, gstate.dev.xsize * sizeof (int));
  1295.  
  1296.     /* Fill the area.  Start at the lowest scan line in the path and loop
  1297.      * until we reach the highest, rendering 8 bits per pixel in each
  1298.      * direction.  Eight bits per pixel horizontally */
  1299.  
  1300.     active = discard = sort = 0;
  1301.     yy = 0;
  1302.     pptr = gstate.dev.buf[0];
  1303.  
  1304.     while (yy < gstate.dev.ysize * 8 + 8)
  1305.     {   memset(xbuf, 0, gstate.dev.xsize);
  1306.  
  1307. if (yy >= gstate.dev.ysize * 8) goto lll;
  1308.  
  1309.         /* Add all the new lines */
  1310.  
  1311.         pline = ybucket[yy];
  1312.         ybucket[yy] = NULL;
  1313.         while (pline)
  1314.         {   lineptr[active++] = pline;
  1315.             pline = pline->chain;
  1316.             sort++;
  1317.         }
  1318.  
  1319.         /* If we have any lines out of order sort them */
  1320.  
  1321.         sort += discard;
  1322.         if (sort != 0)
  1323.         {   count = active;
  1324.             for (;;)
  1325.             {   count = count / 3 + 1;
  1326.                 for (x1 = count; x1 < active; x1++)
  1327.                     for (x2 = x1 - count;
  1328.                          x2 >= 0 &&
  1329.                              lineptr[x2]->xx > lineptr[x2 + count]->xx;
  1330.                          x2 -= count)
  1331.                     {   pline = lineptr[x2];
  1332.                         lineptr[x2] = lineptr[x2 + count];
  1333.                         lineptr[x2 + count] = pline;
  1334.                     }
  1335.                 if (count == 1) break;
  1336.             }
  1337.             active -= discard;
  1338.             discard = sort = 0;
  1339.         }
  1340.  
  1341.         /* Scan convert the scan line */
  1342.  
  1343.         count = active;
  1344.         fdir = 0;
  1345.         ppline = &lineptr[0];
  1346.         xp = -32767;
  1347.  
  1348.         while (count--)
  1349.         {   pline = *ppline++;
  1350.             x1 = pline->xx >> 16;
  1351.  
  1352.             /* At the end of the line draw only its width */
  1353.  
  1354.             if (yy == pline->y2)
  1355.             {   pline->xx += pline->d2;
  1356.                 x2 = pline->xx >> 16;
  1357.                 pline->xx = 0x7fffffff;
  1358.                 discard++;
  1359.                 if (x2 < x1)
  1360.                 {   xx = x1;
  1361.                     x1 = x2;
  1362.                     x2 = xx;
  1363.                 }
  1364.                 if (fdir == 0)
  1365.                 {   s1 = x1;
  1366.                     s2 = x2;
  1367.                 }
  1368.                 else
  1369.                 {   if (x1 < s1) s1 = x1;
  1370.                     if (x2 > s2) s2 = x2;
  1371.                     continue;
  1372.                 }
  1373.             }
  1374.  
  1375.             /* Otherwise draw both the widths and the area enclosed */
  1376.  
  1377.             else
  1378.             {   if      (yy == pline->y1)
  1379.                     pline->xx += pline->d1;  /* Beginning */
  1380.                 else
  1381.                     pline->xx += pline->dx;  /* Middle */
  1382.                 x2 = pline->xx >> 16;
  1383.                 if (x2 < xp) sort++;
  1384.                     xp = x2;
  1385.                 if (x2 < x1)
  1386.                 {   xx = x1;
  1387.                     x1 = x2;
  1388.                     x2 = xx;
  1389.                 }
  1390.                 if      (fdir == 0)          /* Left edge */
  1391.                 {   fdir += pline->fdir;
  1392.                     s1 = x1;
  1393.                     s2 = x2;
  1394.                     continue;
  1395.                 }
  1396.                 if (x1 < s1) s1 = x1;        /* Right edge, or ...  */
  1397.                 if (x2 > s2) s2 = x2;
  1398.                 fdir += pline->fdir;
  1399.                 if      (fdir != 0)          /* Interior */
  1400.                     continue;
  1401.             }
  1402.  
  1403.             /* Draw from s1 to s2 in the x buffer, 8 bits per pixel */
  1404.  
  1405.             xptr1 = xbuf + (s1 >> 3);
  1406.             xptr2 = xbuf + (s2 >> 3);
  1407.             mask1 =  0xff >> (s1 & 7);
  1408.             mask2 = ~0xff >> ((s2 & 7) + 1);
  1409.             if (xptr1 == xptr2)
  1410.                 *xptr1 |= (mask1 & mask2);
  1411.             else
  1412.             {   *xptr1++ |= mask1;
  1413.                 while (xptr1 != xptr2) *xptr1++ = 0xff;
  1414.                 *xptr1 |= mask2;
  1415.             }
  1416.         }
  1417.  
  1418.         /* Pack the x buffer horizontally, 8 bits per pixel */
  1419.  
  1420. lll:
  1421.         xptr1 = xbuf;
  1422.         count = gstate.dev.xsize;
  1423.         s1 = 0;
  1424.         s2 = *((unsigned char *) (xptr1++));
  1425.         while (count--)
  1426.         {   s0 = s1;
  1427.             s1 = s2;
  1428.             s2 = *((unsigned char *) (xptr1++));
  1429.             xshf[count] <<= 1;
  1430.             if (ctbl[s1] ||
  1431.                 ltbl[s1] > rtbl[s0] ||
  1432.                 rtbl[s1] != 0 && rtbl[s1] >= ltbl[s2])
  1433.                 xshf[count] |= 1;
  1434.         }
  1435.  
  1436.         /* After every 8 lines, pack bits vertically onto the page */
  1437.  
  1438.         if (yy > 7 && (yy & 7) == 7)
  1439.         {   pptr1 = pptr;
  1440.             mask1 = 0x80;
  1441.             count = gstate.dev.xsize;
  1442.             while (count--)
  1443.             {   s2 = xshf[count];
  1444.                 s0 = (s2 >> 16) & 0xff;
  1445.                 s1 = (s2 >>  8) & 0xff;
  1446.                 s2 = s2 & 0xff;
  1447.                 if (ctbl[s1] ||
  1448.                     ltbl[s1] > rtbl[s0] ||
  1449.                     rtbl[s1] != 0 && rtbl[s1] >= ltbl[s2])
  1450.                     *pptr1 |= mask1;
  1451.                 if ((mask1 >>= 1) == 0)
  1452.                 {   mask1 = 0x80;
  1453.                     pptr1++;
  1454.                 }
  1455.             }
  1456.             pptr += gstate.dev.xbytes;
  1457.         }
  1458.  
  1459.         yy++;
  1460.  
  1461.     }
  1462.  
  1463.     ybflag = 0;
  1464. }
  1465.  
  1466. /* Scale a line ready for filling */
  1467.  
  1468. void charline(struct point *ppoint)
  1469. {   struct line line;
  1470.     double x1, x2, y1, y2, yy;
  1471.     int fdir;
  1472.  
  1473.     /* We convert the coordinates to fixed point, with a scale factor of
  1474.      * 256, rendering 8 bits per pixel */
  1475.  
  1476.     x1 = floor(ppoint[0].x * 2048.0 + 0.5);
  1477.     x2 = floor(ppoint[1].x * 2048.0 + 0.5);
  1478.     y1 = floor(ppoint[0].y * 2048.0 + 0.5);
  1479.     y2 = floor(ppoint[1].y * 2048.0 + 0.5);
  1480.     
  1481.     /* Make y1 <= y2 */
  1482.  
  1483.     fdir = 1;
  1484.     if (y2 < y1)
  1485.     {   fdir = -1;
  1486.         yy = x1; x1 = x2; x2 = yy;
  1487.         yy = y1; y1 = y2; y2 = yy;
  1488.     }
  1489.  
  1490.     /* Construct the line.  If it is not horizontal calculate the gradient
  1491.      * and the special values of the x displacement for the first and last
  1492.      * lines.  The x coordinates are on a scale of 65536  */
  1493.  
  1494.     line.cdir = 0;
  1495.     line.fdir = fdir;
  1496.     line.xx = x1 * 256.0;
  1497.     line.y1 = ((int) y1) / 256;
  1498.     line.y2 = ((int) y2) / 256;
  1499.     if (line.y2 == line.y1)
  1500.     {   line.dx = 0;
  1501.         line.d1 = 0;
  1502.         line.d2 = (x2 - x1) * 256.0;
  1503.     }
  1504.     else
  1505.     {   yy = (x2 - x1) / (y2 - y1) * 256.0;
  1506.         line.dx = yy * 256.0;
  1507.         line.d1 = ((line.y1 + 1) * 256.0 - y1) * yy;
  1508.         line.d2 = (y2 - line.y2 * 256.0) * yy;
  1509.     }
  1510.  
  1511.     /* Store the line in the line array */
  1512.  
  1513.     checklinesize(lineend + 1);
  1514.     linearray[lineend++] = line;
  1515. }
  1516.  
  1517. /* Set up the x buffers */
  1518.  
  1519. void setxbuf(int size)
  1520. {   int len;
  1521.     if (size > xbsize)
  1522.     {   len = size * (sizeof (int) + sizeof (char)) + 1;
  1523.         xbsize = 0;
  1524.         memfree(memxbeg, memxlen);
  1525.         memxlen = 0;
  1526.         memxbeg = memalloc(len);
  1527.         if (memxbeg == NULL) error(errmemoryallocation);
  1528.         memxlen = len;
  1529.         xshf = memxbeg;
  1530.         xbsize = size;
  1531.     }
  1532.     xbuf = (char *) (xshf + size);
  1533. }
  1534.  
  1535. /* End of file "postfont.c" */
  1536.